package xkp.lesson4;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.List;
/**
 * 子线程接收客户端数据
 * 接收到客户端数据之后，转发给所有人
 */
public class RevThread extends Thread {
    //此处为什么要用static，对于所有的线程对象 终端是共享资源
    private static List<Socket> clientList;
    //接收该socket中的数据
    private Socket socket;
    //输入流
    private DataInputStream dataInputStream;

    public RevThread(Socket socket, List<Socket> clientList) {
        this.socket = socket;
        RevThread.clientList = clientList;
    }

    @Override
    public void run() {
        try {
            dataInputStream = new DataInputStream(socket.getInputStream());
            while (true) {
                //等待接收客户端数据
                //不管两端哪一端强行关闭socket，都会造成读取数据异常
                //注意I/O中的read方法会阻塞，如果没有数据到来，会一直等待
                //造成的缺点每一个客户端的接收都会阻塞，所以服务器在面向多客户端时，不得不使用多线程
                //在BIO(阻塞IO)中，服务器接收多个客户端数据必须使用多线程
                //多线程问题：多线程在进行线程切换是会消耗CPU
                //在使用线程处理客户端数据时，发现大部分时间线程是在等待。
                //线程的利用率非常低
                //针对这么少的工作量，单独启动一个线程不是非常划算。
                //此处我们启动线程主要是为了解决阻塞问题。
                //在提高性能方面：如何做到一个线程处理N多客户端，此时就需要NIO的参与
                //NIO是非阻塞IO   NIO可以工作在阻塞/非阻塞两种状态  即使在阻塞状态，性能也要比BIO高近5倍。
                String revStr = dataInputStream.readUTF();
                System.out.println(socket.getRemoteSocketAddress() + ":" + revStr);
                //转发给所有人
                sendToAll(revStr, clientList);
            }
        } catch (IOException e) {
            //e.printStackTrace();
            //如果出现异常，就是客户端断开
            //移除socket
            clientList.remove(socket);

        } finally {
            try {
                //通知客户端下线
                sendToAll(socket.getRemoteSocketAddress() + "下线", clientList);
                dataInputStream.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }




    public static void sendToAll(String revStr, List<Socket> clientList) throws IOException {
        for (Socket socket : clientList) {
            //此处为是什么要启动线程
            //如果A的网络非常卡，则不启动线程A发完后再给B发....会影响后面的数据传输
            //每一个人都单独线程互补影响.
            new Thread() {
                @Override
                public void run() {
                    try {
                        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                        dataOutputStream.writeUTF(revStr);
                        dataOutputStream.flush();
                    } catch (Exception e) {
                        //遇到异常一般是客户端异常断开
                        clientList.remove(socket);
                    } finally {
                        //释放资源
                    }
                }
            }.start();
        }
    }
}
